package com.gameco.data.service.impl;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gameco.data.service.DataAnalysisService;
import core.ApiResponse;
import core.ResponseMessages;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import util.SM2DecryptionUtil;
import util.XSDUtil;

import java.io.*;
import java.nio.file.Files;
import java.util.Base64;

/**
 * 数据解析服务的实现类，实现了 DataAnalysisService 接口中的方法
 * @author caocc
 * @date 2025.01.17
 */
@Slf4j
@Service
public class DataAnalysisServiceImpl implements DataAnalysisService {

    /**
     * 实现数据解析服务接口方法，对加密数据进行解密、校验，并返回处理后的结果
     * @param xmlEncryptionData 加密的 JSON 数据
     * @param privateKey 用于解密的私钥
     * @return 包含处理结果的 API 响应对象
     */
    @Override
    public ApiResponse<String> DataAnalysis(String xmlEncryptionData,String privateKey) {
        try{
            // 第一步：根据私钥解密 调用 SM2DecryptionUtil 工具类的 decrypt 方法，使用私钥对加密的 JSON 数据进行解密
            String decryptedData = SM2DecryptionUtil.decrypt(privateKey,xmlEncryptionData);
            // 1. 使用 Jackson 解析 JSON 字符串
            ObjectMapper jsonMapper = new ObjectMapper();
            JsonNode jsonNode = jsonMapper.readTree(decryptedData);
            // 获取 codeVersion 值
            String codeVersion = jsonNode.get("codeVersion").asText();
            String xsdStr = "componentMaintReport.xsd";
            if("0.2".equals(codeVersion)){
                xsdStr = "componentMaintReportV2.xsd";
            }
            ClassPathResource xsdResource = new ClassPathResource(xsdStr);
            InputStream inputStream = xsdResource.getInputStream();
            File xsdFile = createTempFile(inputStream, "componentMaintReport", ".xsd");
            // 调用 XSDUtil 工具类的 convertStringToFile 方法，将 JSON 数据转换为 XML 文件
            File xmlFile = XSDUtil.convertStringToFile(decryptedData);

            String xmlContent = Files.readString(xmlFile.toPath());
            try (FileWriter writer = new FileWriter(xmlFile)) {
                writer.write(xmlContent);
            }
            // (数据规范检查)数据结构 XSD 从类路径下获取 XSD 文件资源
            boolean isValid = XSDUtil.validateXMLWithXSD(xmlFile, xsdFile);
            log.info("数据结构是否合法 {}",isValid);
            if(!isValid) {
                // 若数据结构不合法，返回包含错误信息的 API 响应对象
                return ApiResponse.error(ResponseMessages.DATA_ILLEGALITY);
            }

            // 调用 fileToByteArray 方法将 XML 文件转换为字节数组
            byte[] fileByte = fileToByteArray(xmlFile);
            log.info("文件字节 {}", fileByte);

            // 将字节数组转换为 Base64 字符串
            String base64String = Base64.getEncoder().encodeToString(fileByte);
            log.info("Base64 编码后的字符串: {}", base64String);

            // 返回包含 Base64 字符串的成功 API 响应对象
            return ApiResponse.success(base64String);
        }catch (IOException e){
            log.error("文件操作异常: {}", e.getMessage(), e);
            return ApiResponse.error(ResponseMessages.FILE_OPERTOR_ERROR);
        }catch (Exception e){
            log.error("数据解析异常: {}", e.getMessage(), e);
            return ApiResponse.error(ResponseMessages.DATA_PARSING_ERROR);
        }
    }

    private File createTempFile(InputStream inputStream, String prefix, String suffix) throws IOException {
        File tempFile = File.createTempFile(prefix, suffix);
        tempFile.deleteOnExit(); // 程序退出时自动删除临时文件

        try (OutputStream outputStream = new FileOutputStream(tempFile)) {
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        } finally {
            inputStream.close();
        }
        return tempFile;
    }

    /**
     * 将文件转换为字节数组的方法
     * @param file 要转换的文件
     * @return 转换后的字节数组
     * @throws IOException 若文件操作出现异常，抛出该异常
     */
    private byte[] fileToByteArray(File file) throws IOException {
        try (FileInputStream fis = new FileInputStream(file);
             // 创建字节数组输出流，用于存储读取的文件内容
             ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            // 定义缓冲区，用于存储每次读取的文件内容
            byte[] buffer = new byte[1024];
            int len;
            // 循环读取文件内容，直到文件末尾
            while ((len = fis.read(buffer)) != -1) {
                // 将读取的内容写入字节数组输出流
                bos.write(buffer, 0, len);
            }
            // 将字节数组输出流中的内容转换为字节数组并返回
            return bos.toByteArray();
        }
    }

    //------------------------------------------------场景二例子-----------------------------------------------
    // 静态变量，用于保存当前版本号，后续可以改成按照某种规则生成
    @Override
    public ApiResponse<String> DataAnalysisWeb(String data,String codeVersion) {
        try{
            String xsdStr = "componentMaintReport.xsd";
            if("0.2".equals(codeVersion)){
                xsdStr = "componentMaintReportV2.xsd";
            }
            // 第一步:(数据规范检查)数据结构 XSD 从类路径下获取 XSD 文件资源
            ClassPathResource xsdResource = new ClassPathResource(xsdStr);
            InputStream inputStream = xsdResource.getInputStream();
            File xsdFile = createTempFile(inputStream, "componentMaintReport", ".xsd");
            // 调用 XSDUtil 工具类的 convertStringToFile 方法，将 JSON 数据转换为 XML 文件
            File xmlFile = XSDUtil.convertStringToFile(data);

            String xmlContent = Files.readString(xmlFile.toPath());
            xmlContent = xmlContent.replace("<componentMaintReport>", "<componentMaintReport version=\"" + codeVersion + "\">");
            try (FileWriter writer = new FileWriter(xmlFile)) {
                writer.write(xmlContent);
            }

            boolean isValid = XSDUtil.validateXMLWithXSD(xmlFile, xsdFile);
            log.info("数据结构是否合法 {}",isValid);
            if(!isValid) {
                // 若数据结构不合法，返回包含错误信息的 API 响应对象
                return ApiResponse.error(ResponseMessages.DATA_ILLEGALITY);
            }

            // 调用 fileToByteArray 方法将 XML 文件转换为字节数组
            byte[] fileByte = fileToByteArray(xmlFile);
            log.info("文件字节 {}", fileByte);

            // 将字节数组转换为 Base64 字符串
            String base64String = Base64.getEncoder().encodeToString(fileByte);
            log.info("Base64 编码后的字符串: {}", base64String);

            // 返回包含 Base64 字符串的成功 API 响应对象
            return ApiResponse.success(base64String);
        }catch (IOException e){
            log.error("文件操作异常: {}", e.getMessage(), e);
            return ApiResponse.error(ResponseMessages.FILE_OPERTOR_ERROR);
        }catch (Exception e){
            log.error("数据解析异常: {}", e.getMessage(), e);
            return ApiResponse.error(ResponseMessages.DATA_PARSING_ERROR);
        }
    }
}
